home *** CD-ROM | disk | FTP | other *** search
- #!BPY
- """
- Name: 'Billboard Render on Active'
- Blender: 242
- Group: 'Image'
- Tooltip: 'Selected objects and lamps to rendered faces on the act mesh'
- """
- __author__= "Campbell Barton"
- __url__= ["blender", "blenderartist"]
- __version__= "1.0"
-
- __bpydoc__= """\
- Render Billboard Script
- This can texture a simple billboard mesh from any number of selected objects.
-
- Renders objects in the selection to quad faces on the active mesh.
-
- Usage
- * Light your model or enable the shadless flag so it is visible
- * Make a low poly mesh out of quads with 90d corners. (this will be you billboard mesh)
- * Select the model and any lamps that light it
- * Select the billboard mesh so that it is active
- * Run this script, Adjust settings such as image size or oversampling.
- * Select a place to save the PNG image.
- * Once the script has finished running return to the 3d view by pressing Shift+F5
- * To see the newly applied textures change the drawtype to 'Textured Solid'
- """
- # ***** BEGIN GPL LICENSE BLOCK *****
- #
- # Script copyright (C) Campbell J Barton 2006
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of the GNU General Public License
- # as published by the Free Software Foundation; either version 2
- # of the License, or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software Foundation,
- # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- #
- # ***** END GPL LICENCE BLOCK *****
- # --------------------------------------------------------------------------
-
- import Blender
- from Blender import Mesh, Material, Draw
- import BPyMathutils
- import bpy
- import BPyRender
- from Blender.Scene import Render
-
- # reload(BPyRender)
- # reload(BPyMathutils)
-
- import os
- Vector= Blender.Mathutils.Vector
-
- def alpha_mat(image):
- # returns a material useable for
- mtl= bpy.data.materials.new()
- mtl.mode |= (Material.Modes.SHADELESS | Material.Modes.ZTRANSP | Material.Modes.FULLOSA | Material.Modes.TEXFACE | Material.Modes.TEXFACE_ALPHA )
- return mtl
-
- # PupBlock Settings
- GLOBALS= {}
- PREF_RES= Draw.Create(512)
- PREF_TILE_RES= Draw.Create(256)
- PREF_AA = Draw.Create(1)
- PREF_ALPHA= Draw.Create(1)
- PREF_Z_OFFSET = Draw.Create(10.0)
- PREF_IMG_PACK= Draw.Create(1)
-
-
- def save_billboard(PREF_IMAGE_PATH):
- Blender.Window.WaitCursor(1)
- # remove png, add it later
- PREF_IMAGE_PATH= PREF_IMAGE_PATH.replace('.png', '')
-
- ob_sel= GLOBALS['ob_sel']
- me_ob = GLOBALS['me_ob']
- me_data = GLOBALS['me_data']
-
- time= Blender.sys.time()
-
- me_mat= me_ob.matrixWorld
-
- # Render images for all faces
- face_data= [] # Store faces, images etc
- boxes2Pack= []
- me_data.faceUV= True
-
- for i, f in enumerate(me_data.faces):
- no= f.no
-
- # Offset the plane by the zoffset on the faces normal
- plane= [v.co * me_mat for v in f]
-
- # Horizontal stacking, make sure 0,1 and 2,3 are the longest
- if\
- (plane[0]-plane[1]).length + (plane[2]-plane[3]).length < \
- (plane[1]-plane[2]).length + (plane[3]-plane[0]).length:
- plane.append(plane.pop(0))
- rot90= True
- else:
- rot90= False
-
- no= Blender.Mathutils.QuadNormal(*plane)
- plane= [v + no*PREF_Z_OFFSET.val for v in plane]
-
- cent= (plane[0]+plane[1]+plane[2]+plane[3] ) /4.0
- camera_matrix= BPyMathutils.plane2mat(plane)
- tmp_path= '%s_%d' % (PREF_IMAGE_PATH, i)
- img= BPyRender.imageFromObjectsOrtho(ob_sel, tmp_path, PREF_TILE_RES.val, PREF_TILE_RES.val, PREF_AA.val, PREF_ALPHA.val, camera_matrix)
- img.reload()
- #img.pack() # se we can keep overwriting the path
- #img.filename= ""
-
- if rot90:
- f.uv=Vector(1,1), Vector(0,1), Vector(0,0), Vector(1,0)
- else:
- f.uv= Vector(0,1), Vector(0,0), Vector(1,0), Vector(1,1)
-
- if not PREF_IMG_PACK.val:
- f.mode |= Mesh.FaceModes.TEX
- f.image = img
-
- if PREF_ALPHA.val:
- f.transp |= Mesh.FaceTranspModes.ALPHA
- else:
- w= ((plane[0]-plane[1]).length + (plane[2]-plane[3]).length)/2
- h= ((plane[1]-plane[2]).length + (plane[3]-plane[0]).length)/2
-
- face_data.append( (f, img) )
- boxes2Pack.append( [0.0,0.0,h, w, i] )
-
- if PREF_IMG_PACK.val:
- # pack the quads into a square
- packWidth, packHeight = Blender.Geometry.BoxPack2D(boxes2Pack)
-
- render_obs= []
-
- render_mat= alpha_mat(img)
-
- # Add geometry to the mesh
- for box in boxes2Pack:
- i= box[4]
-
- orig_f, img= face_data[i]
-
- # New Mesh and Object
-
- render_me= bpy.data.meshes.new()
-
- render_ob= Blender.Object.New('Mesh')
- render_me.materials= [render_mat]
- render_ob.link(render_me)
-
- render_obs.append(render_ob)
-
- # Add verts clockwise from the bottom left.
- _x= box[0] / packWidth
- _y= box[1] / packHeight
- _w= box[2] / packWidth
- _h= box[3] / packHeight
-
-
- render_me.verts.extend([\
- Vector(_x, _y, 0),\
- Vector(_x, _y +_h, 0),\
- Vector(_x + _w, _y +_h, 0),\
- Vector(_x + _w, _y, 0),\
- ])
-
- render_me.faces.extend(list(render_me.verts))
- render_me.faceUV= True
-
- render_me.faces[0].uv = [Vector(0,0), Vector(0,1), Vector(1,1), Vector(1,0)]
- render_me.faces[0].image = img
-
- # Set the UV's, we need to flip them HOZ?
- for uv in orig_f.uv:
- uv.x = _x + (uv.x * _w)
- uv.y = _y + (uv.y * _h)
-
- target_image= BPyRender.imageFromObjectsOrtho(render_obs, PREF_IMAGE_PATH, PREF_RES.val, PREF_RES.val, PREF_AA.val, PREF_ALPHA.val, None)
- target_image.reload() # incase your overwriting an existing image.
-
- # Set to the 1 image.
- for f in me_data.faces:
- f.image= target_image
- if PREF_ALPHA.val:
- f.transp |= Mesh.FaceTranspModes.ALPHA
-
- # Free the images data and remove
- for data in face_data:
- img= data[1]
- os.remove(img.filename)
- img.reload()
-
- # Finish pack
-
- me_data.update()
- me_ob.makeDisplayList()
- Blender.Window.WaitCursor(0)
- print '%.2f secs taken' % (Blender.sys.time()-time)
-
-
- def main():
- scn= bpy.data.scenes.active
- ob_sel= list(scn.objects.context)
-
- PREF_KEEP_ASPECT= False
-
- # Error Checking
- if len(ob_sel) < 2:
- Draw.PupMenu("Error%t|Select 2 mesh objects")
- return
-
- me_ob= scn.objects.active
-
- if not me_ob:
- Draw.PupMenu("Error%t|No active mesh selected.")
-
- try:
- ob_sel.remove(me_ob)
- except:
- pass
-
- if me_ob.type != 'Mesh':
- Draw.PupMenu("Error%t|Active Object must be a mesh to write billboard images too")
- return
-
- me_data= me_ob.getData(mesh=1)
-
- for f in me_data.faces:
- if len(f) != 4:
- Draw.PupMenu("Error%t|Active mesh must have only quads")
- return
-
-
- # Get user input
- block = [\
- 'Image Pixel Size',\
- ("Packed Size: ", PREF_RES, 128, 2048, "Pixel width and height to render the billboard to"),\
- ("Tile Size: ", PREF_TILE_RES, 64, 1024, "Pixel width and height for each tile to render to"),\
- 'Render Settings',\
- ("Pack Final", PREF_IMG_PACK , "Pack the image for each face into images into a single image"),\
- ("Oversampling", PREF_AA , "Higher quality woth extra sampling"),\
- ("Alpha Clipping", PREF_ALPHA , "Render empty areas as transparent"),\
- ("Cam ZOffset: ", PREF_Z_OFFSET, 0.1, 100, "Distance to place the camera away from the quad when rendering")\
- ]
-
- if not Draw.PupBlock("Billboard Render", block):
- return
-
- # Set globals
- GLOBALS['ob_sel'] = ob_sel
- GLOBALS['me_ob'] = me_ob
- GLOBALS['me_data'] = me_data
-
- Blender.Window.FileSelector(save_billboard, 'SAVE BILLBOARD', Blender.sys.makename(ext='.png'))
- # save_billboard('/tmp/test.png')
-
- if __name__=='__main__':
- main()
-